﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Resources;

namespace IndustrialSmokeCalc
{
    public class OpacityMeasurement
    {
        private const int QUANT = 16;

        public static void GetOpacity(WriteableBitmap ImageSource)
        {
            //StreamResourceInfo sri = Application.GetResourceStream(new Uri("Images/aaa(18).jpg", UriKind.Relative));
            //BitmapImage src = new BitmapImage();
            //src.SetSource(sri.Stream);
            //ImageSource = new WriteableBitmap(src);

            int[] chart = { 20, 40, 60, 80, 100 };

            int[] smokeImage = GetCumulativeHistogram(CropImage(ImageSource, 768, 512, 512, 512));
            //int[] smokeImage = GetCumulativeHistogram(CropImage(ImageSource, 850, 512, 300, 300));
            
            double min = Double.MaxValue;
            int index = -1;
            for (int i = 0; i < 5; i++)
            {
                double has = GetEuclideanDistance(DataSingleton.Instance.ChartHistogram[i], smokeImage);
                if (has < min)
                {
                    min = has;
                    index = i;
                }
            }

            DataSingleton.Instance.RingelmannOpacity = chart[index];
        }

        private static WriteableBitmap CropImage(WriteableBitmap source,
                                                         int xOffset, int yOffset,
                                                         int width, int height)
        {
            // Get the width of the source image
            var sourceWidth = source.PixelWidth;

            // Get the resultant image as WriteableBitmap with specified size
            var result = new WriteableBitmap(width, height);

            // Create the array of bytes
            for (var x = 0; x <= height - 1; x++)
            {
                var sourceIndex = xOffset + (yOffset + x) * sourceWidth;
                var destinationIndex = x * width;

                Array.Copy(source.Pixels, sourceIndex, result.Pixels, destinationIndex, width);
            }

            DataSingleton.Instance.Pic = result;

            return result;
        }

        public static WriteableBitmap ConvertToWbmp(string filename)
        {
            StreamResourceInfo sri = Application.GetResourceStream(new Uri("Images/"+filename, UriKind.Relative));
            BitmapImage src = new BitmapImage();
            src.SetSource(sri.Stream);
            WriteableBitmap bitmapImage = new WriteableBitmap(src);

            return bitmapImage;
        }

        public static int[] GetCumulativeHistogram(WriteableBitmap bitmapImage)
        {
            int[][] arr = getQuant(bitmapImage);
            int[] r = new int[QUANT];
            int[] g = new int[QUANT];
            int[] b = new int[QUANT];

            for (int j = 0; j < arr[0].Length; j++)
            {
                r[arr[0][j]]++;
                g[arr[1][j]]++;
                b[arr[2][j]]++;
            }

            int[] output = new int[r.Length + g.Length + b.Length];
            r.CopyTo(output, 0);
            g.CopyTo(output, r.Length);
            b.CopyTo(output, r.Length + g.Length);
            return output;
        }

        private static int[][] getQuant(WriteableBitmap img)
        {
            int[][] feature = new int[3][];
            int[] r = new int[img.Pixels.Length];
            int[] g = new int[img.Pixels.Length];
            int[] b = new int[img.Pixels.Length];

            for (int i = 0; i < img.Pixels.Length; i++)
            {
                var pixelbytes = BitConverter.GetBytes(img.Pixels[i]);
                r[i] = pixelbytes[0] * (QUANT - 1) / 255;
                g[i] = pixelbytes[1] * (QUANT - 1) / 255;
                b[i] = pixelbytes[2] * (QUANT - 1) / 255;
            }

            feature[0] = r;
            feature[1] = g;
            feature[2] = b;
            return feature;
        }

        private static double GetEuclideanDistance(int[] array1, int[] array2)
        {
            double Sum = 0.0;
            for (int i = 0; i < array1.Length; i++)
            {
                Sum = Sum + Math.Pow((array1[i] - array2[i]), 2.0);
            }
            return Math.Sqrt(Sum);
        }
    }
}
